package cn.lamplet.util.kccu;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class Hex2bin {

    private final Logger logger = LoggerFactory.getLogger(Hex2bin.class);
    private long file_size = 0;
    private long min_addr = 0xffffffffL;
    private long max_addr = 0;
    private long base_addr = 0;
    private long offset_addr = 0;
    private long real_addr = 0;
    private long line_bytes_num = 0;
    private String dir;
    private String hexFileName;
    byte[] bin_array;
    private int segNumber;
    private ArrayList<Integer> segList;
    private ArrayList<String> hexFileList;

    public Hex2bin(String dir, ArrayList<String> hexFileList) {
        this.dir = dir;
        this.hexFileList = hexFileList;
    }

    public Hex2bin() {
    }

    public int handleAddr(String line) {


        if (line.substring(7, 9).equals("04")) {
//            System.out.println("base addr");
            base_addr = Integer.parseInt(line.substring(9, 13), 16);
//            System.out.printf("base_addr 0x%x", base_addr);
            return 0;
        } else if (line.substring(7, 9).equals("00")) {
//            System.out.println("real addr");
            offset_addr = Integer.parseInt(line.substring(3, 7), 16);
            real_addr = (base_addr << 16) + offset_addr;
            line_bytes_num = Integer.parseInt(line.substring(1, 3), 16);
//            System.out.printf("real_addr 0x%x %x ###########\n", real_addr, line_bytes_num);
            return 1;
        } else if (line.substring(7, 9).equals("01")) {
            return -1;
        } else {
            return 2;
        }
    }

    byte[][] bin_array1;

    public void creatArray(int segNumber, ArrayList<Integer> segList) {
        this.segNumber = segNumber;
        this.segList = segList;
        System.out.println("#### " + segNumber + " " + segList);
        bin_array1 = new byte[segNumber][];
        for (int i = 0; i < segNumber; i++) {
            bin_array1[i] = new byte[segList.get(i * 2 + 1)];
            for (int j = 0; j < segList.get(i * 2 + 1); j++) {
                bin_array1[i][j] = (byte) 0xff;
            }
        }
    }

    public void handleMinMaxAddr() {
        if (real_addr < min_addr) {
            min_addr = real_addr;
        }
        if ((real_addr + line_bytes_num - 1) > max_addr) {
            max_addr = real_addr + line_bytes_num - 1;
        }
//        System.out.printf("%x %x $$$$$$$$$\n", min_addr, max_addr);
    }

    long int2Long(int x) {
        return Integer.toUnsignedLong(x);
    }

    public void handleHex2bin2(InputStream inputStream) {

        int ret;
        try {
            List<String> lines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
            for (String line : lines) {
                ret = handleAddr(line);
                if (ret == 1) {
                    for (int i = 0; i < segNumber; i++) {
                        if (real_addr >= int2Long(segList.get(i * 2)) && real_addr < int2Long(segList.get(i * 2)) + int2Long(segList.get(i * 2 + 1)) - 1) {
                            for (int j = 0; j < line_bytes_num; j++) {
                                bin_array1[i][(int) (real_addr - int2Long(segList.get(2 * i)) + j)] = (byte) Integer.parseInt(line.substring((9 + j * 2), (11 + j * 2)), 16);
                            }
                        }

                    }
                } else if (ret < 0) {
                    break;
                }

            }

        } catch (Exception e) {
            logger.error("解析hex文件异常", e);
        }


    }

    public void handleHex2bin1() {
        for (String hexFile : hexFileList) {
            File file = new File(dir, hexFile);
            String line;
            int ret;
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                while ((line = reader.readLine()) != null) {
//                System.out.println(line);
                    ret = handleAddr(line);
                    if (ret == 1) {
                        for (int i = 0; i < segNumber; i++) {
                            if (real_addr >= segList.get(i * 2) && real_addr < segList.get(i * 2) + segList.get(i * 2 + 1) - 1) {
                                for (int j = 0; j < line_bytes_num; j++) {
//                                bin_array1[(int) (real_addr - min_addr + i)] = (byte) Integer.parseInt(line.substring((9 + i * 2), (11 + i * 2)), 16);
//                                    System.out.println(real_addr + ":" + segList.get(2 * i));
                                    bin_array1[i][(int) (real_addr - segList.get(2 * i) + j)] = (byte) Integer.parseInt(line.substring((9 + j * 2), (11 + j * 2)), 16);
                                }
                            }

                        }

                    } else if (ret < 0) {
                        break;
                    }
                }
//                for (int k = 0; k < 1024; k++) {
////                    for (int k = 0; k < segList.get(10 * 2 + 1); k++) {
//                    System.out.printf("0x%02x ", bin_array1[10][k]);
//                    if ((k + 1) % 32 == 0)
//                        System.out.println("");
//                }
//                System.out.println("");
//                System.out.println("seg1:" + segList.get(10 * 2 + 1));

            } catch (Exception e) {
                e.printStackTrace();
            }

//        for (int i = 0; i < file_size; i++) {
//            //System.out.printf("%x", bin_array[i]);
//        }
//        try {
//            OutputStream out = new FileOutputStream(hexFileName.substring(0, hexFileName.lastIndexOf('.')) + ".bin2");
//            out.write(bin_array);
//            out.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        }
    }

    public void handleHex2bin() {
        File file = new File(dir, hexFileName);
        String line;
        int ret;
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            while ((line = reader.readLine()) != null) {
//                System.out.println(line);
                ret = handleAddr(line);
                //   System.out.println(ret);
                if (ret == 1) {
                    handleMinMaxAddr();
                } else if (ret < 0) {
                    break;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getStackTrace());
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        file_size = max_addr - min_addr + 1;
        System.out.printf("%x %x %x\n", min_addr, max_addr, file_size);
        bin_array = new byte[(int) file_size];
        for (int i = 0; i < file_size; i++) {
            bin_array[i] = (byte) 0xff;
        }
        try {
            reader = new BufferedReader(new FileReader(file));
            while ((line = reader.readLine()) != null) {
                ret = handleAddr(line);
                if (ret == 1) {
                    for (int i = 0; i < line_bytes_num; i++) {
                        bin_array[(int) (real_addr - min_addr + i)] = (byte) Integer.parseInt(line.substring((9 + i * 2), (11 + i * 2)), 16);
                    }
                } else if (ret < 0) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (int i = 0; i < file_size; i++) {
            //System.out.printf("%x", bin_array[i]);
        }
        try {
            OutputStream out = new FileOutputStream(hexFileName.substring(0, hexFileName.lastIndexOf('.')) + ".bin2");
            out.write(bin_array);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void getBinArray(byte[] bin, int size) {

//        System.arraycopy(bin_array, 0, bin, OtaBin.otaBinHeadSize, size);
        int offset = 0;
        for (int i = 0; i < segNumber; i++) {
            System.arraycopy(bin_array1[i], 0, bin, OtaBin.otaBinHeadSize + offset, segList.get(2 * i + 1));
            offset += segList.get(2 * i + 1);
        }
    }

    public int getHexFileSize() {
        //  return (int) file_size;
        int fileSize = 0;
        for (int i = 0; i < segNumber; i++) {
            fileSize += segList.get(2 * i + 1);
        }
        return fileSize;
    }

    public int getMinAddr() {
        return (int) min_addr;
    }

    public ArrayList<Integer> handleHexSeg(InputStream inputStream) {
        min_addr = 0xffffffffL;
        max_addr = 0;
        int ret;
        try {
            List<String> lines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
            for (String line : lines) {
//                System.out.println(line);
                ret = handleAddr(line);
                if (ret == 1) {
                    handleMinMaxAddr();
                } else if (ret < 0) {
                    break;
                }
            }
        } catch (Exception e) {
            logger.error("解析hex文件异常", e);
        }
        file_size = max_addr - min_addr + 1;
        System.out.printf("hex seg:%x %x %x\n", min_addr, max_addr, file_size);
        ArrayList<Integer> segAddrSize = new ArrayList<>();
        segAddrSize.add((int) min_addr);
        segAddrSize.add((int) file_size);

        return segAddrSize;
    }
}
